// 渲染进程通用 ESC 分发管理器
// 目标：
// 1) 按“优先级从高到低”处理（数字越大越优先）
// 2) 同优先级“后注册者优先”（LIFO），即最上层组件先处理
// 3) 组件“显示/打开”时注册，“隐藏/关闭/卸载”时注销，避免泄漏与串台（主进程已基于 webContents 选择目标）

/**
 * 概念说明
 * - sourceId: 触发 ESC 的 WebContents.id（仅用于调试/传递，不再用于本地过滤）
 */

// =============== 类型与常量 ===============

/** 事件对象：包含触发来源 */
// =============== 与主进程 ESC 管道对接 ===============
import { shortcutEvents } from './shortcut-events'

export type EscEvent = { sourceId?: number }

/** 处理器类型：返回 true 表示已处理并阻止后续处理 */
export type EscHandler = (e: EscEvent) => boolean | void

/**
 * ESC 优先级（数值越大越优先）
 * - FIND: 查找面板（最高）
 * - MODAL: 弹窗/对话框
 * - OTHER: 其他
 * - CLOSE: 关闭窗口（最低）
 */
export const EscPriority = {
  FIND: 100,
  MODAL: 50,
  OTHER: 10,
  HIDE: 2,
  CLOSE: 1
} as const

/**
 * 注册项（内部结构）
 * - id: 调试标识
 * - priority: 优先级
 * - onEsc: 处理函数，true 表示已处理
 * - ts: 自增时间戳，用于同优先级 LIFO
 */
type RegistryEntry = {
  id: string
  priority: number
  onEsc: EscHandler
  ts: number
}

// =============== 内部状态 ===============

/** 自增时间戳计数器（用于 LIFO） */
let tsCounter = 0

/** 当前窗口内所有已注册的 ESC 处理器 */
const registry: RegistryEntry[] = []

/** 最近一次同步到主进程的优先级（避免重复发送） */
let lastSyncedPriority: number | undefined

/** 计算当前窗口可见处理器的最大优先级（无处理器时为 0） */
function computeMaxPriority(): number {
  if (registry.length === 0) return 0
  return registry.reduce((max, r) => Math.max(r.priority, max), 0)
}

/** 将当前最大优先级同步到主进程（_pre_.tab.setEscPriority） */
function syncEscPriorityIfChanged() {
  try {
    const maxPrio = computeMaxPriority()
    if (lastSyncedPriority !== maxPrio) {
      lastSyncedPriority = maxPrio
      // webContentsId 省略 -> 由 preload 侧默认当前 tab
      _pre_.tab.setEscPriority(maxPrio)
    }
  } catch (error) {
    // 容忍在非预加载环境或测试环境下的缺省
    console.warn('[esc-manager] syncEscPriority failed:', error)
  }
}

// =============== 公共 API ===============

/**
 * 注册 ESC 处理器
 * 调用时机：组件在“显示/打开”时调用；返回的注销函数应在“隐藏/关闭/卸载”时调用
 */
export function register(handler: Omit<RegistryEntry, 'ts'>): () => void {
  const entry: RegistryEntry = { ...handler, ts: ++tsCounter }
  registry.push(entry)
  syncEscPriorityIfChanged()
  return () => {
    const idx = registry.indexOf(entry)
    if (idx !== -1) registry.splice(idx, 1)
    syncEscPriorityIfChanged()
  }
}

/** 手动触发一次优先级重计算与同步（可选） */
export function recomputeAndSync() {
  syncEscPriorityIfChanged()
}

/**
 * 分发 ESC
 * 流程：
 * 1) 收集所有候选处理器（同窗口）
 * 2) 按 priority 降序、ts 降序排序（同优先级后注册者优先）
 * 3) 依次调用 onEsc；当某处理器返回 true 时终止分发
 */
export function dispatch(sourceId?: number): boolean {
  const candidates = registry.slice()
  if (candidates.length === 0) return false
  candidates.sort((a, b) => b.priority - a.priority || b.ts - a.ts)
  for (const h of candidates) {
    try {
      if (h.onEsc({ sourceId })) return true
    } catch (error) {
      // 保持分发链健壮性，吞掉单个处理器异常
      console.warn('[esc-manager] handler error:', error)
    }
  }
  return false
}

// 监听主进程分发到当前窗口的 ESC 事件，转交给本地分发链
shortcutEvents.onEscPress((sourceId?: number) => {
  try {
    dispatch(sourceId)
  } catch (error) {
    console.warn('[esc-manager] dispatch error:', error)
  }
})
